luci-app-chrony: allow non NTS variant also
authorPaul Donald <[email protected]>
Mon, 7 Jul 2025 23:32:39 +0000 (01:32 +0200)
committerPaul Donald <[email protected]>
Mon, 7 Jul 2025 23:32:39 +0000 (01:32 +0200)
Closes #7857

Signed-off-by: Paul Donald <[email protected]>
applications/luci-app-chrony/Makefile
applications/luci-app-chrony/htdocs/luci-static/resources/view/chrony.js
applications/luci-app-chrony/root/usr/share/rpcd/acl.d/luci-app-chrony.json

index 115421529ec6bb6d35b2fa2f281aeb3e0abab9f8..22839a21618a4498f1f0da91d416906f971e885a 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LuCI support for chrony
-LUCI_DEPENDS:=+luci-base +chrony-nts
+LUCI_DEPENDS:=+luci-base +chrony
 
 PKG_LICENSE:=Apache-2.0
 
index 4dcb1525bff6c81c839ec81c2ac1bc95084026ee..fbd123ec8cef036e9e675ed28b02e2b8bcf2aed5 100644 (file)
@@ -7,7 +7,18 @@
 
 return view.extend({
 
-       render(data) {
+       load() {
+               return fs.exec_direct('/usr/sbin/chronyd', ['-v']).then(output => {
+                       const flags = ['IPv6', 'NTP', 'NTS', 'RTC'];
+                       const features = Object.fromEntries(
+                               flags.map(flag => [flag.toLowerCase(), output.includes(`+${flag}`)])
+                       );
+
+                       return features;
+               });
+       },
+
+       render(features) {
                const docUrl = 'https://chrony-project.org/documentation.html';
                let m, s, o;
 
@@ -28,22 +39,24 @@ return view.extend({
                o.nocreate = true;
                o.rmempty = false;
 
-               // NTS
-               s = m.section(form.NamedSection, 'nts', 'nts', _('Network Time Security (NTS)'));
-               s.anonymous = true;
-               s.addremove = true;
+               if (features.nts) {
+                       // NTS
+                       s = m.section(form.NamedSection, 'nts', 'nts', _('Network Time Security (NTS)'));
+                       s.anonymous = true;
+                       s.addremove = true;
 
-               o = s.option(form.Flag, 'rtccheck', _('RTC Check'),
-                       _('Check for the presence of %s.'.format('<code>/dev/rtc0</code>'), 'Check for RTC character device') + '<br/>' +
-                       _('Disables certificate time checks via %s if RTC is absent.'.format('<code>nocerttimecheck</code>') ) );
-               o.default = o.disabled;
+                       o = s.option(form.Flag, 'rtccheck', _('RTC Check'),
+                               _('Check for the presence of %s.'.format('<code>/dev/rtc0</code>'), 'Check for RTC character device') + '<br/>' +
+                               _('Disables certificate time checks via %s if RTC is absent.'.format('<code>nocerttimecheck</code>') ) );
+                       o.default = o.disabled;
 
-               o = s.option(form.Flag, 'systemcerts', _('Use system CA bundle'));
-               o.default = o.enabled;
+                       o = s.option(form.Flag, 'systemcerts', _('Use system CA bundle'));
+                       o.default = o.enabled;
 
-               o = s.option(form.FileUpload, 'trustedcerts', _('Trusted certificates'));
-               o.optional = true;
-               o.root_directory = '/etc';
+                       o = s.option(form.FileUpload, 'trustedcerts', _('Trusted certificates'));
+                       o.optional = true;
+                       o.root_directory = '/etc';
+               }
 
                // Stepping
                s = m.section(form.NamedSection, 'makestep', 'makestep', _('Stepping'), 
@@ -120,7 +133,7 @@ return view.extend({
                        _('Remote NTP servers for your chronyd'));
                s.anonymous = true;
                s.addremove = true;
-               insertTypedSectionOptions(m, s, o, 'server');
+               insertTypedSectionOptions(m, s, o, 'server', features);
 
                // Pool entries
                s = m.section(form.TypedSection, 'pool', _('Pool'),
@@ -128,7 +141,7 @@ return view.extend({
                        _('The pool name is expected to resolve to multiple addresses which might change over time.'));
                s.anonymous = true;
                s.addremove = true;
-               insertTypedSectionOptions(m, s, o, 'pool');
+               insertTypedSectionOptions(m, s, o, 'pool', features);
 
                // Peer entries
                s = m.section(form.TypedSection, 'peer', _('Peer'),
@@ -136,20 +149,20 @@ return view.extend({
                        _('A single symmetric association allows the peers to be both servers and clients to each other.'));
                s.anonymous = true;
                s.addremove = true;
-               insertTypedSectionOptions(m, s, o, 'peer');
+               insertTypedSectionOptions(m, s, o, 'peer', features);
 
                // Servers assigned (to us) via DHCP
                s = m.section(form.NamedSection, 'dhcp_ntp_server', 'dhcp_ntp_server', _('DHCP(v6)'),
                        _('Options for servers provided to this host via DHCP(v6) (via the WAN for example).'));
                s.anonymous = true;
-               insertTypedSectionOptions(m, s, o, 'dhcp_ntp_server');
+               insertTypedSectionOptions(m, s, o, 'dhcp_ntp_server', features);
 
 
                return m.render();
        }
 });
 
-function insertTypedSectionOptions(m, s, o, type) {
+function insertTypedSectionOptions(m, s, o, type, features) {
 
                o = s.option(form.Flag, 'disabled', _('Disabled'));
                o.default = o.disabled; // disabled default is disabled i.e., enabled
@@ -166,10 +179,12 @@ function insertTypedSectionOptions(m, s, o, type) {
                        o.default = o.disabled
                        o.depends('disabled', '0');
 
-                       o = s.option(form.Flag, 'nts', _('NTS'));
-                       o.rmempty = true;
-                       o.default = o.disabled
-                       o.depends('disabled', '0');
+                       if (features.nts) {
+                               o = s.option(form.Flag, 'nts', _('NTS'));
+                               o.rmempty = true;
+                               o.default = o.disabled
+                               o.depends('disabled', '0');
+                       }
                }
 
                o = s.option(form.Flag, 'prefer', _('Prefer'));
index 397f18f231b7cc6599124f465bee22d04aa6fe85..637f7c6ce2dabaa7b1a580d93b2672f5a425fa11 100644 (file)
@@ -2,6 +2,9 @@
        "luci-app-chrony": {
                "description": "Grant UCI access for luci-app-chrony",
                "read": {
+                       "file": {
+                               "/usr/sbin/chronyd -v" : [ "exec" ]
+                        },
                        "uci": [ "chrony" ]
                },
                "write": {